home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-11-08 | 18.8 KB | 670 lines | [TEXT/KAHL] |
- //------------------------- © 1991-1995 by James G. Stout --------------------------
- // File : cdefTog.c
- // Date : November 2,1991
- // Author : Jim Stout
- // Purpose : A CDEF to implement Tog's buttons
- // : use procID : 1104 * 16 + varCode
- // : when calling NewControl() or in your resource template.
- // : This CDEF supports the System 7 style gray drawing of an
- // : inactive control and the useWindFont varCode.
- // :
- // : If you find a use for this, I'd love to know about it. Bug reports
- // : are always interesting.
- // :
- // : Internet : JimS@WRQ.COM(work hours, PST)
- // : AppleLink : WRQ (daily)
- // : CompuServe : 73240,2052 (weekly or so)
- // : AOL : JasG (weekly or so)
- // : eWorld : Jim Stout (weekly or so)
- //----------------------------------------------------------------------------------
-
- //#define _DEBUGCDEF 1 // allows inline debugging in a test project
- #define _USEOFFSCREEN 1
- #define _EMBOSS 1
-
- #include "fatCDEF.h"
-
- #include <Controls.h>
- #include <LowMem.h>
- #include <GestaltEqu.h>
- #include <Memory.h>
- #include <QDOffscreen.h>
- #include <ToolUtils.h>
- #include <Traps.h>
- #include <Types.h>
-
- #include "colorCDEF.h"
- #include "grayCDEF.h"
- #include "miscCDEF.h"
-
- #include "cdefTog.h"
-
- #ifdef _DEBUGCDEF
- pascal long CDmain (short varCode, ControlHandle theCtl, short message, long param);
- pascal long CDmain (short varCode, ControlHandle theCtl, short message, long param)
- #else
-
- //==================================================================================
- // CDEF main
- //==================================================================================
-
- pascal long main (short varCode, ControlHandle theCtl, short message, long param)
- #endif
- {
- long ret = 0L;
- Point p;
- GrafPtr thisPort;
- CDEFHandle hCdef;
- SignedByte cState, dState;
-
- #include "fatEntry.c"
-
- cState = HGetState((Handle)theCtl);
- HLock((Handle)theCtl);
- if((**theCtl).contrlData) {
- dState = HGetState((**theCtl).contrlData);
- HLock((**theCtl).contrlData);
- }
-
- //----------------------------------------------------------------------------------
- // Process messages to control
- //----------------------------------------------------------------------------------
-
- switch(message) {
-
- case initCntl:
- GetPort(&thisPort);
- hCdef = (CDEFHandle)NewHandle(sizeof(CDEFData));
- if(hCdef) {
- (**hCdef).txFont = thisPort->txFont;
- (**hCdef).txSize = thisPort->txSize;
- (**theCtl).contrlData = (Handle)hCdef;
- dState = HGetState((**theCtl).contrlData);
- HLock((**theCtl).contrlData);
- }
- break;
-
- case dispCntl:
- if((**theCtl).contrlData) {
- HUnlock((**theCtl).contrlData);
- DisposeHandle((**theCtl).contrlData);
- (**theCtl).contrlData = 0;
- }
- break;
-
- case drawCntl:
- if((**theCtl).contrlVis != 0 &&
- ((WindowPeek)(**theCtl).contrlOwner)->visible)
- doDraw(theCtl, varCode);
- break;
-
- case testCntl:
- p.v=HiWord(param);
- p.h=LoWord(param);
- if(PtInRect(p,&(*theCtl)->contrlRect)) {
- ret = 1;
- }
- break;
-
- case calcCRgns:
- RectRgn((RgnHandle)(param & 0x7fffffffL), &(*theCtl)->contrlRect);
- break;
-
- case calcCntlRgn:
- case calcThumbRgn:
- RectRgn((RgnHandle)(param), &(*theCtl)->contrlRect);
- break;
- }
-
- if((**theCtl).contrlData)
- HSetState((**theCtl).contrlData, dState);
- HSetState((Handle)theCtl, cState);
-
- #include "fatExit.c"
-
- return (ret);
- }
-
- //==================================================================================
- // If running with System 7, use DeviceLoop to gracefully handle multiple screens.
- // Simulate DeviceLoop if using System 6...
- //==================================================================================
-
- static void doDraw(ControlHandle theCtl, short varCode)
- {
- short saveMode, txF, txS;
- unsigned char saveFace;
- GrafPtr savePort, thisPort;
- devLoopHandle hDl;
- RgnHandle saveClip, hRgn;
- DeviceLoopDrawingUPP drawControlUPP;
-
- //----------------------------------------------------------------------------------
- // set window font & size info
- //----------------------------------------------------------------------------------
- GetPort(&savePort);
- SetPort((**theCtl).contrlOwner);
- GetPort(&thisPort);
-
- saveMode = thisPort->txMode;
- saveFace = thisPort->txFace;
-
- if(!(varCode & useWindFont)) { // use system font
- txF = thisPort->txFont; // save current
- txS = thisPort->txSize;
- TextFont(LMGetSysFontFam()); // set system as current
- TextSize(LMGetSysFontSize());
- TextFace(normal);
- }
- TextMode(srcOr);
-
- //----------------------------------------------------------------------------------
- // Create our data handle to pass to DeviceLoop
- //----------------------------------------------------------------------------------
-
- hDl = (devLoopHandle)NewHandle(sizeof(devLoopData));
- if(hDl) {
- drawControlUPP = NewDeviceLoopDrawingProc(drawControl);
-
- (**hDl).theCtl = theCtl;
- (**hDl).varCode = varCode;
- (**hDl).controlRect = (**theCtl).contrlRect;
-
- //----------------------------------------------------------------------------------
- // Do the clip region properly. Thanks Ari!
- //----------------------------------------------------------------------------------
-
- saveClip = NewRgn();
- GetClip(saveClip);
-
- hRgn = NewRgn();
- RectRgn(hRgn, &(**hDl).controlRect);
- SectRgn(saveClip, hRgn, hRgn);
-
- if(EmptyRgn(hRgn)) { // if empty, don't waste
- DisposeRgn(saveClip); // time drawing...
- DisposeRgn(hRgn);
- return;
- }
-
- //----------------------------------------------------------------------------------
- // Call DeviceLoop to take care of our drawing
- //----------------------------------------------------------------------------------
-
- if(getOSVers() >= 0x0700) {
- DeviceLoop (hRgn, drawControlUPP, (long)hDl, 0);
- }
- else {
- sys6DeviceLoop (hRgn, drawControlUPP, (long)hDl, 0);
- }
-
- SetClip(saveClip);
- DisposeRgn(hRgn);
- DisposeHandle((Handle)hDl);
- DisposeRoutineDescriptor(drawControlUPP);
- }
-
- //----------------------------------------------------------------------------------
- // restore window font & size info
- //----------------------------------------------------------------------------------
-
- if(!(varCode & useWindFont)) {
- TextFont(txF);
- TextSize(txS);
- }
- TextMode(saveMode);
- TextFace(saveFace);
- SetPort(savePort);
- }
-
- //==================================================================================
- // main drawing routine for all variations of the control. Also
- // handles setting of colors, inactive control drawing.
- //
- // This is called by DeviceLoop, but in this case, we just pay attention to the
- // "depth" and "userData" parameters.
- //==================================================================================
-
- pascal void drawControl (short depth, short dFlags, GDHandle theDevice, long userData)
- {
-
- #pragma unused(dFlags, theDevice)
-
- ControlHandle theCtl;
- short varCode, qdVers, lnHt, lnAdj;
- OSErr err;
- Rect ctlRect, offRect;
- FontInfo f;
- PenState savePen;
- Boolean grayOK = false, inColor = false, inactive = false, bwPort = true;
- Boolean bgInColor = false, useOffscreen = false;
- RGBColor saveFore={0,0,0}, saveBack={-1,-1,-1}, rgbGray;
- GrafPtr thisPort;
- CGrafPtr savePort, offPort=0;
- GDHandle saveDevice;
- PixMapHandle offPix;
- CDEFHandle hCdef;
- devLoopHandle hDl;
-
- //----------------------------------------------------------------------------------
- // Can we draw?
- //----------------------------------------------------------------------------------
-
- hDl = (devLoopHandle)userData; // need control & varCode
- if(hDl) {
- theCtl = (**hDl).theCtl;
- varCode = (**hDl).varCode;
- }
- else
- return;
-
- hCdef = (CDEFHandle)(**theCtl).contrlData;
- if(!hCdef)
- return;
-
- //----------------------------------------------------------------------------------
- // Initialize for drawing
- //----------------------------------------------------------------------------------
-
- if(varCode & useWindFont)
- varCode ^= useWindFont;
-
- if((*theCtl)->contrlHilite == 255)
- inactive = true;
-
- GetPort(&thisPort);
- ctlRect = offRect = (*theCtl)->contrlRect;
-
- if((thisPort->txFont != (**hCdef).txFont) || // if font changed,
- (thisPort->txSize != (**hCdef).txSize)) { // clear rect to erase
- (**hCdef).txFont = thisPort->txFont; // old font
- (**hCdef).txSize = thisPort->txSize;
- (**hCdef).txFace = thisPort->txFace;
- EraseRect(&ctlRect);
- }
-
- GetPenState(&savePen);
-
- //----------------------------------------------------------------------------------
- // Should we draw in color?
- //
- // What kind of port are we drawing to ? DeviceLoop may have called us with a
- // depth > 1, but for an old-style 1 bit port ( but the GDevice is multi-bit).
- //
- // If so, then set depth to 1 unless we have Color Quickdraw and want to use
- // offscreen drawing to force color controls in the old style grafport.
- //----------------------------------------------------------------------------------
-
- if((((CGrafPtr)thisPort)->portVersion & 0x8000)) // have a color grafPort
- bwPort = false;
-
- #ifdef _USEOFFSCREEN
-
- qdVers = getQDVers();
-
- if(bwPort && qdVers < gestalt32BitQD12) // can't force colors
- depth = 1; // in b&w port unless
- // we have ColorQD
- #else
-
- if(bwPort)
- depth = 1;
-
- #endif
-
- if(depth > 2) { // either color port or
- inColor = true; // color GDevice
- saveColors(&saveFore, &saveBack);
- bgInColor = true;
- if(saveBack.red == 65535 && // is bg white?
- saveBack.green == 65535 &&
- saveBack.blue == 65535)
- bgInColor = false;
- }
-
- //----------------------------------------------------------------------------------
- // Figure out how we should draw - offscreen or not...
- //----------------------------------------------------------------------------------
-
- #ifdef _USEOFFSCREEN
-
- if(inColor && qdVers >= gestalt32BitQD12) { // can use GWorlds
- if(bwPort) // to get 3D in b&w ports
- useOffscreen = true;
- else
- if(bgInColor) // or to avoid flicker on
- useOffscreen = true; // control titles
- }
-
- //----------------------------------------------------------------------------------
- // Can we draw off screen ?
- //----------------------------------------------------------------------------------
-
- if(useOffscreen) {
- err = NewGWorld(&offPort, 0, &offRect, nil, nil, 0L);
- if(err == noErr && offPort) { // got offscreen port
- offPix = getLockedPixels(&offPort, qdVers); // get pixels
- if(offPix) {
- GetGWorld(&savePort, &saveDevice); // save old port stuff
- SetGWorld(offPort, nil); // set to offscreen port
- SetOrigin(offRect.left, offRect.top); // and initialize it...
- RGBForeColor(&saveFore);
- RGBBackColor(&saveBack);
- TextFont(thisPort->txFont);
- TextSize(thisPort->txSize);
- TextFace(thisPort->txFace);
- TextMode(srcOr);
- EraseRect(&offRect);
- }
- else {
- DisposeGWorld(offPort);
- offPort = 0;
- }
- }
- else
- offPort = 0;
- }
-
- #endif // _USEOFFSCREEN
-
- //----------------------------------------------------------------------------------
- // Set a 1 by 1, solid pattern pen for our drawing.
- //----------------------------------------------------------------------------------
-
- PenSize(1,1);
- PenPat( (ConstPatternParam) "\xff\xff\xff\xff\xff\xff\xff\xff");
-
- //----------------------------------------------------------------------------------
- // Get font info so the title lines up correctly
- //----------------------------------------------------------------------------------
-
- GetFontInfo(&f); // needed for title routine
- lnAdj = f.descent + f.leading;
- lnHt = f.ascent + lnAdj;
-
- //----------------------------------------------------------------------------------
- // Draw the control title, in cTextColor or gray if it is inactive
- //----------------------------------------------------------------------------------
-
- if(inColor) {
-
- #ifdef _EMBOSS
- if(bgInColor) {
- ForeColor(whiteColor);
- drawTitle (theCtl, &offRect, lnHt, lnAdj, EMBOSS, !PUSHED);
- }
- #endif
-
- setPartColor(theCtl, cTextColor, true);
- grayOK = getGray(&rgbGray);
- if(grayOK && inactive)
- RGBForeColor(&rgbGray);
- }
-
- drawTitle(theCtl, &offRect, lnHt, lnAdj, NORMAL, !PUSHED);
-
- //----------------------------------------------------------------------------------
- // If we drew offscreen, restore the onscreen port and blit the control title.
- //----------------------------------------------------------------------------------
-
- #ifdef _USEOFFSCREEN
-
- if(offPort) {
- SetGWorld(savePort, saveDevice);
-
- //----------------------------------------------------------------------------------
- // Use CopyBits to get the titles onscreen (avoiding flicker on embossed titles).
- //----------------------------------------------------------------------------------
-
- restoreColors(&saveFore, &saveBack);
-
- if((**theCtl).contrlTitle[0])
- CopyBits( &WINBITMAP( offPort ), &WINBITMAP( savePort ),
- &offRect, &ctlRect, transparent, nil );
-
- unlockPixels(offPix, qdVers);
- DisposeGWorld(offPort);
- }
-
- #endif // _USEOFFSCREEN
-
- //----------------------------------------------------------------------------------
- // Draw control indicator directly to the screen
- //----------------------------------------------------------------------------------
-
- if(inColor) {
- RGBBackColor(&saveBack); // background
- setPartColor(theCtl, cFrameColor, true); // foreground
- grayOK = getGray(&rgbGray);
- if(grayOK && inactive)
- RGBForeColor(&rgbGray);
- }
-
- drawTog(theCtl, &ctlRect, inColor);
-
- //----------------------------------------------------------------------------------
- // gray inactive controls the System 6 way if needed (couldn't get gray for title)
- //----------------------------------------------------------------------------------
-
- if(!grayOK && inactive) { // gray out the old way
- PenPat( (ConstPatternParam) "\xAA\x55\xAA\x55\xAA\x55\xAA\x55");
- PenMode(patBic);
- ctlRect.left+=18; // not the indicator area
- ClipRect(&ctlRect);
- PaintRect(&ctlRect);
- }
-
- //----------------------------------------------------------------------------------
- // Clean up and leave
- //----------------------------------------------------------------------------------
-
- if(inColor)
- restoreColors(&saveFore, &saveBack);
- SetPenState(&savePen);
- }
-
- //==================================================================================
- // The "Tog Button" drawing routine
- //==================================================================================
-
- static void drawTog(ControlHandle theCtl, Rect *offRect, Boolean inColor)
- {
- Rect r;
- Point p;
- short i,x,y;
- RGBColor saveFore,rgbA = {0xAAAA,0xAAAA,0xAAAA};
- GrafPtr thisPort;
-
- GetPort(&thisPort);
-
- // Draw the diamond shaped control
-
- if(inColor)
- GetForeColor(&saveFore);
-
- r = *offRect;
- p.h = r.left+2; // get pen loc for drawing
- p.v = r.bottom - (r.bottom - r.top)/2 - 1;
-
- MoveTo(p.h,p.v); // button frame
- LineTo(p.h+7,p.v+7);
- LineTo(p.h+14,p.v);
- LineTo(p.h+7,p.v-7);
- LineTo(p.h,p.v);
-
- ForeColor(whiteColor); // erase center
- if(!inColor)
- BackColor(whiteColor); // just to be sure…
- MoveTo(p.h+1,p.v);
- Line(6,-6);
- for(i=0;i<6;i++) {
- Move(0,1);
- Line(-5,5);
- Move(0,1);
- Line(6,-6);
- }
- if(!inColor)
- ForeColor(blackColor);
-
- if(inColor) {
- RGBForeColor(&rgbA); // add 3D shading
- MoveTo(p.h,p.v-1);
- LineTo(p.h+7, p.v-8);
- LineTo(p.h+14, p.v-1);
- ForeColor(whiteColor);
- Move(0,2);
- LineTo(p.h+8, p.v+7);
- Move(-2,0);
- LineTo(p.h,p.v+1);
-
- RGBForeColor(&saveFore);
- }
-
- if((*theCtl)->contrlHilite == 1) { // hilited button
- MoveTo(p.h+1,p.v);
- LineTo(p.h+7,p.v+6);
- LineTo(p.h+13,p.v);
- LineTo(p.h+7,p.v-6);
- LineTo(p.h+1,p.v);
- }
-
- if((*theCtl)->contrlValue != OFF) { // button center
- x = p.h+4;
- y = p.v;
- for(i=1;i<=4;i++) {
- MoveTo(x,y);
- LineTo(x+3,y+3);
- x++;
- y--;
- }
- x = p.h+5;
- y = p.v;
- for(i=1;i<=3;i++) {
- MoveTo(x,y);
- LineTo(x+2,y+2);
- x++;
- y--;
- }
- }
- }
- //==================================================================================
- // Draw the control titles - handles multiple lines and 3D embossing
- //==================================================================================
-
- static void drawTitle (ControlHandle theCtl, Rect *offRect, short lnHt,
- short lnAdj, Boolean emboss, Boolean pushed)
- {
- Rect r;
- short inx=1,lnCnt=1,lnSpace,ctlSpace,v,h,adj=0;
- Str255 s;
-
- r = *offRect;
-
- do { // count number of lines
- if((*theCtl)->contrlTitle[inx++] == 0x0d)
- lnCnt++;
- }while (inx <= (*theCtl)->contrlTitle[0]);
-
- lnSpace = lnCnt * lnHt; // required space
- ctlSpace = r.bottom - r.top; // available height
- v = r.bottom; // baseline
- v-=(ctlSpace - lnSpace)/2; // minus free space
- v-=lnAdj; // minus descent+leading
- v-=((lnCnt-1)*lnHt); // minus other lines
- // v is now base for line 1
- for(inx=1;inx<=lnCnt;inx++) {
- getNextLine((*theCtl)->contrlTitle, s, inx);
- if(s[0]) {
- h = r.left + 20;
- if(emboss & pushed)
- adj = -1;
- else
- if(emboss)
- adj = 1;
-
- MoveTo(h+adj, v+adj);
- DrawString(s);
- }
- v+=lnHt;
- }
- }
- //==================================================================================
- // Grab the next line of a control title (assumes lines separated by CR)
- //==================================================================================
-
- static void getNextLine(Str255 t, Str255 s, short line)
- {
- short inx=1,len=0,lnCnt=1;
-
- s[0] = 0; // always default to null string
-
- do {
- if(t[inx] == 0x0d) // next line
- lnCnt++;
- else
- if(lnCnt == line) { // return this line
- len++;
- s[0] = len;
- s[len] = t[inx];
- }
- inx++;
- }while (inx <= t[0]);
- }
-
-
- #ifdef _USEOFFSCREEN
-
- //==================================================================================
- // Lock down the offPort pixels and return a locked handle to the locked pixels
- //==================================================================================
-
- static PixMapHandle getLockedPixels(CGrafPtr * offPort, short qdVers)
- {
- PixMapHandle pmHdl;
-
- if(qdVers >= gestalt32BitQD13) { // no bug in the
- pmHdl = GetGWorldPixMap(*offPort); // GetGWorldPixMap routine
- if(!LockPixels(pmHdl)) {
- pmHdl = 0;
- }
- }
- else
- pmHdl = (*offPort)->portPixMap;
-
- if(pmHdl)
- HLock((Handle)pmHdl);
- return(pmHdl);
- }
-
- //==================================================================================
- // Unlock PixMapHandle & pixels
- //==================================================================================
-
- static void unlockPixels(PixMapHandle pmHdl, short qdVers)
- {
- if(pmHdl) {
- HUnlock((Handle)pmHdl);
- if(qdVers >= gestalt32BitQD13) { // no bug in the
- UnlockPixels(pmHdl); // GetGWorldPixMap routine
- }
- }
- }
-
- //==================================================================================
- // Return QD version number from Gestalt
- //==================================================================================
-
- static short getQDVers()
- {
- OSErr err;
- long gResult;
-
- if(trapAvailable(_Gestalt)) {
- err = Gestalt(gestaltQuickdrawVersion,&gResult);
- if(err == noErr)
- return(LoWord(gResult));
- }
- return(gestaltOriginalQD);
- }
-
- #endif // _USEOFFSCREEN